package core.servlets;

import static core.util.StoredData.REFRESH_COUNTER;
import static core.util.StoredData.storedSessionData;
import static core.util.Utilities.COOKIE_NAME;
import static core.util.Utilities.generateUniqueSessionId;
import static core.util.Utilities.redirectPage;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jdt.core.compiler.InvalidInputException;

import core.util.MyCookieValue;
import core.util.PageText;
import core.util.StoredData;
import core.util.UserSessionData;

public class HomeServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;

    private static final long serverStartTime = System.currentTimeMillis();

    private static final String servletAddr;
    static {
        java.net.InetAddress host = null;
        try {
            host = java.net.InetAddress.getLocalHost();
        } catch( UnknownHostException e ) {
            e.printStackTrace();
        } finally {
            servletAddr = (host == null) ? "server1" : host.getHostAddress();
        }
    }

    private static AtomicInteger requestCounter = new AtomicInteger( 0 );

    private static AtomicInteger uniqueCounter = new AtomicInteger( 0 );

    @Override
    public void doGet( HttpServletRequest request, HttpServletResponse response )
            throws ServletException, IOException {
        if( requestCounter.compareAndSet( REFRESH_COUNTER, 0 ) ) {
            // remove stale session data
            StoredData.removeStaleSessionData();
        }

        // get cookies
        Cookie[] cookies = request.getCookies();
        String location = "location";

        // get session id from request
        String sessionId;
        try {
            sessionId = generateUniqueSessionId( request, servletAddr,
                    serverStartTime, uniqueCounter );
        } catch( NoSuchAlgorithmException e1 ) {
            e1.printStackTrace();
            throw new ServletException( e1 );
        }

        MyCookieValue cookieValue = null;
        // get our cookie
        Cookie cookie = null;
        if( cookies != null ) {
            for( Cookie c : cookies ) {
                cookie = c;
                if( COOKIE_NAME.equalsIgnoreCase( cookie.getName() ) ) {
                    try {
                        cookieValue = new MyCookieValue( cookie.getValue() );
                        break;
                    } catch( InvalidInputException e ) {
                        e.printStackTrace();
                        throw new ServletException( e );
                    }
                }
            }
        }

        // no cookie found in request, this is a new session
        if( cookieValue == null || !StoredData.isCookieFresh( cookieValue ) ) {
            cookieValue = createNewCookieValue( sessionId, location );
            cookie = new Cookie( COOKIE_NAME, cookieValue.toString() );
            UserSessionData data = new UserSessionData( 0, "Hello, User!",
                    cookieValue );
            storedSessionData.put( cookieValue.getSessionId(), data );
        }
        // if the cookie is not new and not valid (i.e. version mismatch),
        // show error page
        else if( !StoredData.isCookieValid( cookieValue ) ) {
            redirectPage( response, "error.html" );
        }

        processRequest( cookie, response, cookieValue );
        UserSessionData data = storedSessionData.get( cookieValue
                .getSessionId() );

        response.setContentType( "text/html" );
        PrintWriter out = response.getWriter();

        out.println( PageText.getHomeHTML( data.getDisplayNumber(),
                data.getDisplayText() ) );
    }

    /**
     * Begin processing request
     * 
     * @param cookieValue
     */
    private void processRequest( Cookie cookie, HttpServletResponse response,
            MyCookieValue cookieValue ) {

        String sessionId = cookieValue.getSessionId();
        UserSessionData data = storedSessionData.get( sessionId );

        // increase version number on cookie value
        cookieValue.increaseVersion();

        // add cookie to session data
        data.setCookieValue( cookieValue );
        // set last active time
        data.setLastActiveTime( System.currentTimeMillis() );
        // increase display count
        data.increaseDisplayNumber();

        // update cookie and attach to response
        cookie.setValue( cookieValue.toString() );
        response.addCookie( cookie );
    }

    private MyCookieValue createNewCookieValue( String sessionId,
            String location ) {
        return new MyCookieValue( sessionId, 0, location );
    }
}
